package com.kingyea.mobilepolice.systemsync;

import com.alibaba.fastjson.JSON;
import com.kingyea.mobilepolice.system.StateCode;
import com.kingyea.mobilepolice.system.exception.BusinessException;
import com.kingyea.mobilepolice.systemsync.bean.InvokedMethod;
import com.kingyea.mobilepolice.util.GlobalVar;
import org.apache.activemq.command.ActiveMQQueue;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.jms.Destination;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 把需要同步的系统操作发送到mq
 *
 * @author Mr.Lin
 * @version v1.0.0
 * @description
 * @date Created in 2018/3/1 16:31
 */
@Component
//@ConfigurationProperties( prefix = "spring.activemq")
@Aspect
public class Send2QueueAspect {
    private static final Logger logger = LoggerFactory.getLogger(Send2QueueAspect.class);

    /**
     * 待发送队列
     */
    public static LinkedBlockingQueue<String> toBeSentQueue = new LinkedBlockingQueue();
    public static Pattern pattern = Pattern.compile("(?<=\\()[^\\)]+");
    @Autowired
    private MQProducer mqProducer;

    @SuppressWarnings("unchecked")
    @After(value = "@annotation(Send2Queue)" /*, argNames = "JoinPoint,Send2Queue"*/)
    public void sendEvent(final JoinPoint joinPoint/*, final Send2Queue send2Queue*/) throws Exception {

        if (GlobalVar.inside != null) {//内外网的都需要拦击token操作存入队列
//            System.out.println("Controller.inside:"+GlobalVar.inside+">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
            final InvokedMethod invokedMethod = new InvokedMethod();


            // 1.获取操作的当前类名 获取切面的class名
            final String targetName = joinPoint.getTarget().getClass().getCanonicalName();


            invokedMethod.setClazzName(targetName);

            // 2.获取操作的方法名
            final String methodName = joinPoint.getSignature().getName();
            invokedMethod.setMethodName(methodName);
            // 3.获得参数列表
            final Object[] arguments = joinPoint.getArgs();
            // 4.获得参数个数
            invokedMethod.setAttributeNumber(arguments.length);
            // 5.给传递参数赋值
            final Object[] params = new Object[arguments.length];
            for (int i = 0; i < arguments.length; i++) {
                params[i] = arguments[i];
            }
            invokedMethod.setParams(params);

            final List<String> typesStrList = new ArrayList<>();
            Matcher matcher = pattern.matcher(joinPoint.getSignature().toLongString());
            while (matcher.find()) {
                String typesStr = matcher.group();
                if (typesStr.indexOf(",") != -1) {
                    String[] typeStrs = typesStr.split(",");
                    for (String typeStr : typeStrs) {
                        typesStrList.add(typeStr);
                    }
                } else {
                    typesStrList.add(typesStr);
                }
            }
            invokedMethod.setTypeStrList(typesStrList);
            if (invokedMethod.getAttributeNumber().intValue() != invokedMethod.getTypeStrList().size()) {
                throw new BusinessException(StateCode.SYSTEM_ERROR, "拦截到的service有误,传入参数数量与形参数量不一致!!! ");
            }


            String message = JSON.toJSONString(invokedMethod);

            try {
                Destination destination;
                /** 针对token操作有一个专门的 mq队列名 ; 其余的数据操作mq用统一队列名称 */
                if (methodName.endsWith("RedisService")) {
                    destination = new ActiveMQQueue(GlobalVar.MQ_SUBJECT_TOKEN);// 针对token操作有一个专门的 mq队列名
                } else {
                    destination = new ActiveMQQueue(GlobalVar.MQ_SUBJECT);// 其余的数据操作mq用统一队列名称
                }
                String targetServiceStr = toBeSentQueue.peek();// 发送成功前，获取不移除
                while (targetServiceStr != null) {
                    mqProducer.sendMessage(destination, targetServiceStr);
                    toBeSentQueue.poll();// 发送成功后，获取并移除
                    targetServiceStr = toBeSentQueue.peek();
                }

                mqProducer.sendMessage(destination, message);

                if (logger.isInfoEnabled()) {
                    logger.info("InvokedMethod{} is send", message);
                } else if (logger.isDebugEnabled()) {
                    logger.debug("InvokedMethod{} is send", message);
                }
            } catch (Exception e) {
                e.printStackTrace();
                logger.error("队列消息发送失败{}：" + e.getLocalizedMessage(), message);
                toBeSentQueue.offer(message);
            }


        }

    }


}
